/*
The MIT License (MIT)

Copyright (c) 2013 Mike Dapiran, Brian May, Richard Pospesel, and Bert Wierenga

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software 
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "DX11Director.h"
#include <D3D11.h>


#include "tinyxml.h"
#include "Hogshead.Common.h"
#include "Hogshead.Core.h"
#include "Hogshead.BulletPhysics.h"

#include "../Managers/DX11Manager.h"

#include "../HLSLCPPDeclarations/ConstantBuffers.fx"
#include "../HLSLCPPDeclarations/Lighting.fx"
#include "../HLSLCPPDeclarations/Texture2DMappings.fx"

#include "../Directors/IProcess.h"
#include "../Processes/MeshProcess.h"
#include "../Processes/GUIProcess.h"
#include "../Processes/ShadowMapGenerationProcess.h"
#include "../Processes/ParticleProcess.h"

#include "../Components/Camera.h"

#include "../Components/PointLight.h"
#include "../Components/DirectionalLight.h"
#include "../Components/SpotLight.h"

#include "../Components/MeshRenderer.h"
#include "../Components/GUITexture.h"
#include "../Components/GUIButton.h"

#include "../Messages/ConstantBufferModifier.h"

#include "../Content/BlendState.h"
#include "../Content/SamplerState.h"
#include "../Content/VertexShader.h"
#include "../Content/PixelShader.h"

#include "../Content/Texture.h"



namespace Hogshead
{
	namespace DX11Rendering
	{
		DirectorCPP(Hogshead::DX11Rendering::DX11Director)

		const float DX11Director::far_clip_radius = 20000.0f;

		DX11Director::DX11Director(void) : _pl_bin(MAX_POINT_LIGHT, MAX_POINT_LIGHT), _dl_bin(MAX_DIRECTIONAL_LIGHT, MAX_DIRECTIONAL_LIGHT),
			_sl_bin(MAX_SPOT_LIGHT, MAX_SPOT_LIGHT), _shadow_generator(NULL), _cull_frustrum(NULL),  _scene_wide_srv_list(8, 8)
		{
			_active_camera = 0;
			
			for( int i = 0; i < 8; i++ )
				_rtv_bin.add( NULL );

			for( int j = 0; j < 128; j++ )
				_clear_array[j] = NULL;
		}


		DX11Director::~DX11Director(void)
		{
		}

		void DX11Director::handle_constant_buffer_modifier(IMessageReceiver* receiver, IMessage* message)
		{
			DX11Director* me = (DX11Director*)(receiver);
			me->_constant_buffer_group.handleConstantBufferModifier( message->as<ConstantBufferModifier>() );
		}

		void DX11Director::handle_culling_message(IMessageReceiver* receiver, IMessage* message)
		{
			DX11Director* _this = (DX11Director*)(receiver);
			
			CullingMessage* cull_message = message->as<CullingMessage>();
			const ArrayList<GameObject*>& nonculled_objects = cull_message->getGameObjects();
			
			//clear our non culled objects
			_this->_nonculled_components.clear();
			for(int i = 0; i < nonculled_objects.size(); i++)
			{
				/*
				Array1D<MeshRenderer*> mesh_renderers = nonculled_objects[i]->getComponentsOfType<MeshRenderer>();
				for(int j = 0; j < mesh_renderers.length(); j++)
				{
					_this->_nonculled_components.add(mesh_renderers[j]);
				}
				*/
				GameObject* go = nonculled_objects[i];
				int count = go->componentCount();
				for(int j = 0; j < count; j++)
				{
					if(MeshRenderer* mr =  go->getComponent(j)->as<MeshRenderer>())
						_this->_nonculled_components.add(mr);
					if(PointLight* pl = go->getComponent(j)->as<PointLight>())
						_this->_nonculled_components.add(pl);
					if(SpotLight* sl = go->getComponent(j)->as<SpotLight>())
						_this->_nonculled_components.add(sl);
				}

			}

		}


		void DX11Director::finalize()
		{
			if(_cull_frustrum)
				Messenger::unregisterReceiver<CullingMessage>(this, _cull_frustrum);

			for(int i = 0; i < _processes.size(); i++)
			{
				Factory::release( _processes[i] );
			}
			_processes.clear();
			_lit_meshes.clear();
			_shadow_generator = NULL;

			for( int i = 0; i < _scene_wide_srv_list.size(); i++ )
			{
				ContentLibrary::release( _scene_wide_srv_list[i].first );
			}
			_scene_wide_srv_list.clear();
		}

		// read in xml
		IDirector* DX11Director::readXML(const String& in_xml)
		{
			//parse the String for what we need
			TiXmlDocument document;
			document.Parse(in_xml);

			TiXmlElement* root_element = document.RootElement();
			String root_tag(root_element->Value());

			if(root_tag.equals("Director"))
			{
				TiXmlNode* child_node = NULL;
				TiXmlElement* child_element;
				int render_target_blend_desc_index = 0;
				while(child_node = root_element->IterateChildren(child_node))
				{
					child_element = child_node->ToElement();
					if(!child_element)
						continue;

					String tag(child_element->Value());
					if(tag.equals("Process"))
					{
						String type = child_element->Attribute("type");
						if(type)
						{
							if(type.equals("MeshProcess"))
							{
								//acquire one
								MeshProcess* mesh_process = Factory::acquire<MeshProcess>();

								//call read xml on it
								String process_xml(*child_element);
								mesh_process->readXML( process_xml );
								
								//add it to process list
								_processes.add( mesh_process );
							}
							else if(type.equals("GUIProcess"))
							{
								//acquire one
								GUIProcess* gui_process = Factory::acquire<GUIProcess>();

								//call read xml on it
								String process_xml(*child_element);
								gui_process->readXML( process_xml );
								
								//add it to process list
								_processes.add( gui_process );
							}
							else if(type.equals("ShadowMapGenerationProcess"))
							{
								//acquire one
								ShadowMapGenerationProcess* shadow_process = Factory::acquire<ShadowMapGenerationProcess>();

								//call read xml on it
								String process_xml(*child_element);
								shadow_process->readXML( process_xml );
								
								//add it to process list
								_processes.add( shadow_process );
							}
							else if(type.equals("ParticleProcess"))
							{
								//acquire one
								ParticleProcess* particle_process = Factory::acquire<ParticleProcess>();

								//call read xml on it
								String process_xml(*child_element);
								particle_process->readXML( process_xml );
								
								//add it to process list
								_processes.add( particle_process );
							}
							else
							{
								error("Unknown Process type");
							}
						}
					}
					else if(tag.equals("ConstantBufferGroup"))
					{
						//hand the correct xml block to our ConstantBufferGroup
						//so that it can create itself.
						_constant_buffer_group.readXML( String(*child_element) );
					}

					
					else if(tag.equals("RenderingTextureBuffer"))
					{
						//get the name and add an empty to the lookup table with the name as the key.
						String name;
						child_element->QueryStringAttribute("name", &name);
						_rendering_buffers.add( name, RenderingTextureBuffer() );

						//grab the sub xml block and pass it on to the texture to build itself from.
						String xml_to_pass(*child_element);
						_rendering_buffers[name].readXML( xml_to_pass );
					}
					else if(tag.equals("ShaderResourceTexture"))
					{
						//this is a SRV we want to leoad from file, get the path and load it
						String file_path;
						child_element->QueryStringAttribute("path", &file_path);
						
						int reg;
						child_element->QueryIntAttribute("register", &reg);

						

						//load it and hold the reference
						int index = _scene_wide_srv_list.size();
						_scene_wide_srv_list.add( Pair<Texture*, int>() );

						_scene_wide_srv_list[index].first = ContentLibrary::explicitLoad<Texture>(file_path, file_path);
						_scene_wide_srv_list[index].second = reg;
					}
				}
			}

			return this;
		}

		

		void DX11Director::initialize()
		{
			//setup
			ZeroMemory(&_lighting_info, sizeof( LightingInfo ));
		
			this->registerMessageCallback<ConstantBufferModifier>(DX11Director::handle_constant_buffer_modifier);
			this->registerMessageCallback<CullingMessage>(DX11Director::handle_culling_message);

			
			if(_cull_frustrum = this->_active_camera->getParentGameObject()->getComponentOfType<CullingFrustum>())
				Messenger::registerReceiver<CullingMessage>(this, _cull_frustrum);
			else
				error("DX11Director requires a CullingFrustum");
			
			
			//initialize the processes
			for(int i = 0; i < _processes.size(); i++)
			{
				_processes[i]->setParentDirector( this );
				_processes[i]->initialize();				
				if( _processes[i]->is<ShadowMapGenerationProcess>() )
				{
					_shadow_generator = _processes[i]->as<ShadowMapGenerationProcess>();
				}
			}

			
		}

		void DX11Director::update(const GameTimer& in_gt)
		{
			
			for(int i = 0; i < _processes.size(); i++)
			{
				_processes[i]->update(in_gt);
			}
			
		}

		void DX11Director::draw()
		{
			fillOutLighting(this->_active_camera, &this->_nonculled_components);

			//bind any constant buffers the director has
			for( int j = 0; j < _constant_buffer_group.size(); j++ )
			{
				DX11Manager::bindConstantBuffer( _constant_buffer_group.get(j).buffer(),
					_constant_buffer_group.get(j).registerNumber(),
					_constant_buffer_group.get(j).shaderBindFlags() );
			}
			
			for(int i = 0; i < _processes.size(); i++)
			{
				if( !_processes[i]->enabled() )
					continue;

				
#pragma region Pre-Render setup
				if( !_processes[i]->is<ShadowMapGenerationProcess>())
				{
					//clear out old info
					_rtv_bin.clear();
					_srv_bin.clear();
					_dsv_bin = NULL;

					//hout << endl << " started binding textures" << endl;
					DX11Manager::setPSShaderResourcesCustom( _clear_array, 128, 0 );
					DX11Manager::setRenderTargetsCustom(NULL, 0, NULL);

					//do the setup for any SRV's that were loaded form file
					for( int srv_index = 0; srv_index < _scene_wide_srv_list.size(); srv_index++ )
					{
						//hout << "bound any textures per scene" << endl;
						DX11Manager::setShaderResources( _scene_wide_srv_list[srv_index].second, &_scene_wide_srv_list[srv_index].first->_shader_resource_view, (ShaderBindFlags)(DOMAIN_SHADER | PIXEL_SHADER) );
					}

					//do the setup for RenderingTextureBuffers

					bool render_to_back_buffer = false;
					int start_reg = MAP_COUNT;
				
					//find the info out for this process.
					Vector<TEXTURE_BINDING_INFO>& textures = _processes[i]->getTextureRequests();

					//clear any that need to be cleared
					//then bind them
					for( int k = 0; k < textures.size(); k++ )
					{
						if( textures[k].usage == RENDER_TARGET_VIEW )
						{
							if( textures[k].name.equals("Back Buffer") )
							{
								render_to_back_buffer = true;
								if( textures[k].clear )
								{
									DX11Manager::clearBackBuffer( textures[k].clear_data.color );
									//hout << "cleared back buffer" << endl;
								}
							}
							else
							{
								//clear as requested
								if( textures[k].clear )
								{
									DX11Manager::clearRenderTarget( _rendering_buffers[ textures[k].name ].renderTargetView(), 
									textures[k].clear_data.color );
									//hout << "cleared some other Render target " << endl;
								}

								//make sure there is enough space to place the RTV
								while( _rtv_bin.size() <= textures[k].send_to_register )
									_rtv_bin.add( NULL );

								//place the RTV, index matches register
								_rtv_bin[ textures[k].send_to_register ] = _rendering_buffers[ textures[k].name ].renderTargetView();
							}
						}
						else if( textures[k].usage == SHADER_RESOURCE_VIEW )
						{
							if( _shadow_generator && textures[k].name.equals("Shadow Maps"))
							{			
								_srv_bin.clear();

								start_reg = textures[k].send_to_register;

								//make sure there is enough space to place the SRV's
								while( _srv_bin.size() < 24 )
									_srv_bin.add( NULL );

								//we know there are 24 of them
								for( int j = 0; j < 24; j++ )
								{
									//bind each one
									ID3D11ShaderResourceView* temp = _shadow_generator->getShadowMaps()[j].shaderResourceView();
									if(temp)
										_srv_bin[ j ] = temp;
									else
										_srv_bin[ j ] = NULL;
								}							
								DX11Manager::setPSShaderResourcesCustom( (ID3D11ShaderResourceView*const*) _srv_bin, _srv_bin.size(), start_reg );
								//hout << " set shadow maps" << endl;
							}
							else
							{
								//place the SRV, index matches register
								ID3D11ShaderResourceView* item = _rendering_buffers[ textures[k].name ].shaderResourceView();
								DX11Manager::setPSShaderResourcesCustom( &item, 1, textures[k].send_to_register );
								//hout << "set some other SRV " << endl;
							}
						}
						else if( textures[k].usage == DEPTH_STENCIL_VIEW )
						{						
							if( textures[k].name.equals("Depth Buffer") )
							{
								render_to_back_buffer = true;
								if( textures[k].clear )
								{
									DX11Manager::clearDepthBuffer( textures[k].clear_data.depth_stencil.flags,
									textures[k].clear_data.depth_stencil.depth,
									textures[k].clear_data.depth_stencil.stencil );

									//hout << " cleared The depth buffer " << endl;
								}
							}
							else
							{
								if( textures[k].clear )
								{
									DX11Manager::clearDepthStencil( _rendering_buffers[ textures[k].name ].depthStencilView(), textures[k].clear_data.depth_stencil.flags,
										textures[k].clear_data.depth_stencil.depth, textures[k].clear_data.depth_stencil.stencil );
									//hout << " cleared some other DSV" << endl;
								}

								_dsv_bin = _rendering_buffers[ textures[k].name ].depthStencilView();
							}
						}
					}
					//bind the requested textures

					//do SRV's
				
					//do RTV's/DSV
					if( render_to_back_buffer )
					{
						DX11Manager::setRenderTargetsStandard( &_rtv_bin, _rtv_bin.size() );
						//hout << "set standard RTV(s)" << endl;
					}
					else
					{
						DX11Manager::setRenderTargetsCustom( &_rtv_bin, _rtv_bin.size(), _dsv_bin);
						//hout << "set some custom RTV(s)" << endl;
					}

#pragma endregion
				}
				//now do the render
				_processes[i]->render(_active_camera, &_nonculled_components);
				//hout << StringBuilder() << "did a " << _processes[i]->name() << " render" << endl;
				
			}
			DX11Manager::setRenderTargetsStandard(NULL, 0);
			DX11Manager::present();
			//hout << "Presented" << endl << endl;
		}

		void DX11Director::setActiveCamera(Camera* in_camera)
		{
			_active_camera = in_camera;
		}
		
		void DX11Director::registerComponent(Hogshead::Core::IComponent* in_component)
		{
			//check if it is a camera, set it to active camera. Last one to register
			//becomes the active one.
			if( in_component->is<Camera>() )
			{
				_active_camera = (Camera*) in_component;
			}
			//see if it is a light we need to hold onto
			else if( in_component->is<PointLight>() )
			{
				_point_lights.add( (PointLight*)in_component );
			}
			else if( in_component->is<DirectionalLight>() )
			{
				_directional_lights.add( (DirectionalLight*)in_component );
			}
			else if( in_component->is<SpotLight>() )
			{
				_spot_lights.add( (SpotLight*)in_component );
			}
			//look to see if it is a MeshRenderer and wants lighting info
			else if( in_component->is<MeshRenderer>())
			{

				_registered_components.add( in_component );

				MeshRenderer* mesh_renderer = in_component->as<MeshRenderer>();
				//handle those that want lighting
				if( mesh_renderer->useLighting() )
				{
					_lit_meshes.add( mesh_renderer );
					//pass the component on to each MeshProcess
					for(int i = 0; i < _processes.size(); i++)
					{
						//check to see if this process is a MeshProcess and if it has the name that the component is looking for.
						auto& iter =  mesh_renderer->_techniques.getEnumerator();

						while(iter.moveNext())
						{
							if(_processes[i]->handle() == iter.current().first )
							{
								_processes[i]->registerComponent( mesh_renderer );
							}
						}
					}
				}
				//handle those that don't
				else
				{
					_unlit_meshes.add( mesh_renderer );
					//pass the component on to each MeshProcess
					for(int i = 0; i < _processes.size(); i++)
					{
						//check to see if this process is a MeshProcess and if it has the name that the component is looking for.
						auto& iter =  mesh_renderer->_techniques.getEnumerator();

						while(iter.moveNext())
						{
							if(_processes[i]->handle() == iter.current().first )
							{
								_processes[i]->registerComponent( mesh_renderer );
							}
						}
						
					}
				}
			}
			else if(in_component->is<GUITexture>() || in_component->is<GUIButton>())
			{
				//_registered_components.add( in_component );

				GUIComponent* gui_component = (GUIComponent*) in_component;

				for(int i = 0; i < _processes.size(); i++)
				{
					if(_processes[i]->is<GUIProcess>() && _processes[i]->handle() == gui_component->meshProcessHandle())
					{
						_processes[i]->registerComponent(gui_component);
					}
				}
			}
		}


		void DX11Director::unregisterComponent(Hogshead::Core::IComponent* in_component)
		{
			//check if it is a camera, set it to active camera. Last one to register
			//becomes the active one.

			//see if it is a light we need to hold onto
			if( in_component->is<PointLight>() )
			{
				_point_lights.swapRemove((PointLight*)in_component);
			}
			else if( in_component->is<DirectionalLight>() )
			{
				_directional_lights.swapRemove( (DirectionalLight*)in_component );
			}
			else if( in_component->is<SpotLight>() )
			{
				_spot_lights.swapRemove( (SpotLight*)in_component );
			}
			//look to see if it is a MeshRenderer and wants lighting info
			else if(MeshRenderer* mesh_renderer = in_component->as<MeshRenderer>())
			{
				if(_lit_meshes.contains(mesh_renderer))
					_lit_meshes.remove(mesh_renderer);
				for( int i = 0 ; i < _processes.size(); i++ )
				{
					_processes[i]->unregisterComponent( mesh_renderer );
				}
			}
			else if(in_component->is<GUITexture>())
			{
				_registered_components.swapRemove( in_component );

				GUITexture* gui_texture = in_component->as<GUITexture>();

				for(int i = 0; i < _processes.size(); i++)
				{
					if(_processes[i]->is<GUIProcess>())
					{
						_processes[i]->unregisterComponent(gui_texture);
					}
				}
			}
		}


		void DX11Director::writePointLight(LightingInfo* in_lighting_info, PointLight* in_point_light, int in_index) const
		{
			//position
			in_lighting_info->_point_lights[in_index]._position_ws = Vector4(in_point_light->getPosition(),1.0f);
			
			//colors
			in_lighting_info->_point_lights[in_index]._ambient_color = in_point_light->ambient;
			in_lighting_info->_point_lights[in_index]._diffuse_color = in_point_light->diffuse;
			in_lighting_info->_point_lights[in_index]._specular_color = in_point_light->specular;

			//attenuation
			in_lighting_info->_point_lights[in_index]._attenuation_coefficients.x = in_point_light->a0;
			in_lighting_info->_point_lights[in_index]._attenuation_coefficients.y = in_point_light->a1;
			in_lighting_info->_point_lights[in_index]._attenuation_coefficients.z = in_point_light->a2;
			in_lighting_info->_point_lights[in_index]._attenuation_coefficients.W = 1.0f;

			in_lighting_info->_point_lights[in_index]._fast_falloff.x = in_point_light->fast_falloff_start;
			in_lighting_info->_point_lights[in_index]._fast_falloff.y = in_point_light->fast_falloff_end;

			in_lighting_info->_point_lights[in_index]._fast_falloff.z = 0.0f;
			in_lighting_info->_point_lights[in_index]._fast_falloff.W = 1.0f;

			

		}

		 void DX11Director::writeDirectionalLight(LightingInfo* in_lighting_info, DirectionalLight* in_directional_light, int in_index) const
		 {
			//direction
			in_lighting_info->_directional_lights[in_index]._direction_ws = Vector4(in_directional_light->getDirection(), 1.0f);

			//colors
			in_lighting_info->_directional_lights[in_index]._ambient_color = in_directional_light->ambient;
			in_lighting_info->_directional_lights[in_index]._diffuse_color = in_directional_light->diffuse;
			in_lighting_info->_directional_lights[in_index]._specular_color = in_directional_light->specular;
			 
			//shadows
			in_lighting_info->_directional_lights[in_index]._vp = in_directional_light->shadowProjection() * in_directional_light->shadowView();
			
			in_lighting_info->_directional_lights[in_index]._produce_shadow_map = Vector4(0.0f, 0.0f, 0.0f, 0.0f);

			if( in_directional_light->enabledShadows() )
					in_lighting_info->_directional_lights[in_index]._produce_shadow_map.x = 1.0f;
			else
				in_lighting_info->_directional_lights[in_index]._produce_shadow_map.x = 0.0f;
		 }

		void DX11Director::writeSpotLight(LightingInfo* in_lighting_info, SpotLight* in_spot_light, int in_index) const
		{
			//position
			in_lighting_info->_spot_lights[in_index]._position_ws = Vector4(in_spot_light->getPosition(),1.0f);
			in_lighting_info->_spot_lights[in_index]._direction_ws_power_pair= Vector4(in_spot_light->getDirection(), in_spot_light->power);
			
			//colors
			in_lighting_info->_spot_lights[in_index]._ambient_color = in_spot_light->ambient;
			in_lighting_info->_spot_lights[in_index]._diffuse_color = in_spot_light->diffuse;
			in_lighting_info->_spot_lights[in_index]._specular_color = in_spot_light->specular;

			//attenuation
			in_lighting_info->_spot_lights[in_index]._attenuation_coefficients.x = in_spot_light->a0;
			in_lighting_info->_spot_lights[in_index]._attenuation_coefficients.y = in_spot_light->a1;
			in_lighting_info->_spot_lights[in_index]._attenuation_coefficients.z = in_spot_light->a2;
			in_lighting_info->_spot_lights[in_index]._attenuation_coefficients.W = 1.0f;

			in_lighting_info->_spot_lights[in_index]._fast_falloff.x = in_spot_light->fast_falloff_start;
			in_lighting_info->_spot_lights[in_index]._fast_falloff.y = in_spot_light->fast_falloff_end;

			in_lighting_info->_spot_lights[in_index]._fast_falloff.z = 0.0f;
			in_lighting_info->_spot_lights[in_index]._fast_falloff.W = 1.0f;

			//vp 
			in_lighting_info->_spot_lights[in_index]._vp = in_spot_light->shadowProjection() * in_spot_light->shadowView();

			//shadow map?
			in_lighting_info->_spot_lights[in_index]._produce_shadow_map = Vector4(0.0f, 0.0f, 0.0f, 0.0f);
			if( in_spot_light->enabledShadows() )
				in_lighting_info->_spot_lights[in_index]._produce_shadow_map.x = 1.0f;
			else
				in_lighting_info->_spot_lights[in_index]._produce_shadow_map.x = 0.0f;
		}

		void DX11Director::writeBlackPointLight(LightingInfo* in_lighting_info, int in_index) const
		{
			//colors
			in_lighting_info->_point_lights[in_index]._ambient_color = Color::black_clear;
			in_lighting_info->_point_lights[in_index]._diffuse_color = Color::black_clear;
			in_lighting_info->_point_lights[in_index]._specular_color = Color::black_clear;
			
		}

		void DX11Director::writeBlackDirectionalLight(LightingInfo* in_lighting_info, int in_index) const
		{
			//colors
			in_lighting_info->_directional_lights[in_index]._ambient_color = Color::black_clear;
			in_lighting_info->_directional_lights[in_index]._diffuse_color = Color::black_clear;
			in_lighting_info->_directional_lights[in_index]._specular_color = Color::black_clear;
		}

		
		void DX11Director::writeBlackSpotLight(LightingInfo* in_lighting_info, int in_index) const
		{
			//colors
			in_lighting_info->_spot_lights[in_index]._ambient_color = Color::black_clear;
			in_lighting_info->_spot_lights[in_index]._diffuse_color = Color::black_clear;
			in_lighting_info->_spot_lights[in_index]._specular_color = Color::black_clear;
		}
		

		void DX11Director::determinePointLights( HashSet<void*>* in_nonculled_components )
		{
			_pl_bin.clear();
			//check if we have collided with each light, if we have, use it
			for(int i = 0; i < _point_lights.size(); i++)
			{
				if(in_nonculled_components->contains(_point_lights[i]))
					_pl_bin.add(_point_lights[i]);
				
				if(_pl_bin.size() >= MAX_POINT_LIGHT)
					break;
			}		
				
			
			//copy over the PointLights we have 
			for( int j = 0; j < MAX_POINT_LIGHT; j++ )
			{
				if( j < _pl_bin.size() )
				{
					writePointLight( &_lighting_info, _pl_bin[j], j );
				}
				else
				{
					//fill rest black
					writeBlackPointLight( &_lighting_info, j );
				}
			}					
	
		}

		void DX11Director::determineDirectionalLights( Camera* in_camera)
		{
			_dl_bin.clear();
			//figure out DirectionalLight info
			if(_directional_lights.size() <= MAX_DIRECTIONAL_LIGHT)
			{
				//add each one then add black lights to the rest later
				for(int j = 0; j < _directional_lights.size(); j++)
				{
					_dl_bin.add( _directional_lights[j] );
				}
			}
			else
			{
				//there are more lights then we can send to the card so we 
				//need to let the designer know there is an issue
				error("There are too many Directional Lights in the current Scene.");
			}

			//Copy over the DirectionalLights we have 
			for( int j = 0; j < MAX_DIRECTIONAL_LIGHT; j++ )
			{
				if( j < _directional_lights.size() )
				{
					writeDirectionalLight( &_lighting_info, _directional_lights[j], j );
				}
				else
				{
					//fill rest black
					writeBlackDirectionalLight( &_lighting_info, j );
				}
			}
		}

		void DX11Director::determineSpotLights( HashSet<void*>* in_nonculled_components )
		{
			_sl_bin.clear();
			//check if we have collided with each light, if we have, use it
			for(int i = 0; i < _spot_lights.size(); i++)
			{
				if(in_nonculled_components->contains(_spot_lights[i]))
					_sl_bin.add(_spot_lights[i]);

				if(_sl_bin.size() >= MAX_SPOT_LIGHT)
					break;
			}
			
				
			//copy over the PointLights we have 
			for( int j = 0; j < MAX_SPOT_LIGHT; j++ )
			{
				if( j < _sl_bin.size() )
				{
					writeSpotLight( &_lighting_info, _sl_bin[j], j );
				}
				else
				{
					//fill rest black
					writeBlackSpotLight( &_lighting_info, j );
				}
			}					
						
		}

		void DX11Director::fillOutLighting(Camera* _active_camera, HashSet<void*>* in_nonculled_components)
		{
			//update info
			determineDirectionalLights( _active_camera );
			determinePointLights( in_nonculled_components );
			determineSpotLights( in_nonculled_components );

			//update the buffer
			DX11Manager::updateConstantBuffer( DX11Manager::getLightingConstantBuffer() , &_lighting_info );
		}

		const LightingInfo& DX11Director::getLighting() const
		{
			//update the buffer
			DX11Manager::updateConstantBuffer( DX11Manager::getLightingConstantBuffer() , &_lighting_info );
			return _lighting_info;
		}

		void DX11Director::updateSpecularExponent(float in_specular_exponent)
		{
			_lighting_info._specular_exponent.x = in_specular_exponent;
			_lighting_info._specular_exponent.y = in_specular_exponent;
			_lighting_info._specular_exponent.z = in_specular_exponent;
			_lighting_info._specular_exponent.W = in_specular_exponent;

			//hout << StringBuilder() << "changed to " << in_specular_exponent << endl;
		}

	}
}